/* 
** (Copyright) sejishikong <sejishikong@263.net>
** Authors:    sejishikong <sejishikong@263.net>
**             Wei Lian <lianwei2003.student@sina.com> 
** Maintainer: Wei Lian
**    This program is free software; you can redistribute it and/or modify
**    it under the terms of the GNU General Public License Version 2 as
**    published by the Free Software Foundation;
**
**    This program is distributed in the hope that it will be useful,
**    but WITHOUT ANY WARRANTY; without even the implied warranty of
**    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**    GNU General Public License for more details.
**
**    You should have received a copy of the GNU General Public License
**    along with this program; if not, write to the Free Software
**    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
**
*/
#include "header.h"
#include "fork.h"
#include "sys.h"
#include "config.h"
#include "mainwindow.h"
#include "mystatusbar.h"

Fork::Fork(QObject * parent, const char *name):QObject(parent, name),
mainwindow(static_cast < Sopcast * >(parent))
{

    sop = new QProcess(this);
    connect(sop, SIGNAL(readyReadStdout()), this, SLOT(parsestdout()));
    connect(sop, SIGNAL(processExited()), this, SLOT(onsopexit()));

    player = new QProcess(this);
    connect(player, SIGNAL(processExited()), this, SLOT(onplayerexit()));

    snstatus = 0;

    echotimer = new QTimer(this);
    connect(echotimer, SIGNAL(timeout()), this, SLOT(echo()));

}


Fork::~Fork()
{
    if (snstatus)
	delete snstatus;
    killsop();
    killplayer();
}


////fork new process
bool Fork::forksop(QString url, QString name)
{
    channelurl = url;
    channelname = name;
    mainwindow->statusbar->showMessage("Connecting...");

    int i;
    char inport[8];
    int sock;
    ///choose inport and outport number
    for (i = 8000; i < 9000; i++) {
	sock = Sys::connect_to_server("127.0.0.1", i);
	if (sock == -1)
	    break;
	else if (sock >= 0)
	    ::close(sock);
    }
    sprintf(inport, "%d", i);
    mainwindow->vboxconfig->labelinport->setText(inport);

    for (i = 9000; i < 10000; i++) {
	sock = Sys::connect_to_server("127.0.0.1", i);
	if (sock == -1)
	    break;
	else if (sock >= 0)
	    ::close(sock);
    }
    sprintf(outport, "%d", i);
    mainwindow->vboxconfig->labeloutport->setText(outport);
    ////    
    sop->clearArguments();
    sop->addArgument("sp-sc");
    sop->addArgument(url);
    sop->addArgument(inport);
    sop->addArgument(outport);
    return sop->start();
}


bool Fork::forkplayer()
{
    player->clearArguments();
    QStringList strlst = QStringList::split(" ",
					    mainwindow->vboxconfig->
					    editplayer->text());
    for (QStringList::Iterator it = strlst.begin(); it != strlst.end();
	 ++it) {
	player->addArgument(*it);
    }

    QString url = "http://localhost:";
    url += outport;
    player->addArgument(url);
    return player->start();
}


////kill process
void Fork::killsop()
{
    if (sop->isRunning()) {
//      sop->tryTerminate ();
	sop->kill();
    }
}


void Fork::killplayer()
{
    if (player->isRunning()) {
	player->tryTerminate();
    }
}


/////////////slots
void Fork::onplayerexit()
{
    mainwindow->buttonplayer->setPaletteForegroundColor(Qt::black);

    if (snstatus && mainwindow->buttonplayer->isOn()
	&& !player->isRunning()) {
	if (forkplayer() == TRUE)
	    mainwindow->buttonplayer->setPaletteForegroundColor(Qt::blue);
	else
	    fprintf(stderr, "failed to launch player!\n");
    }

}


void Fork::onsopexit()
{
    mainwindow->statusbar->showMessage("");
    channelname = "";
    channelurl = "";
}


void Fork::parsestdout()
{
    QString str, str1, str2, threadstate;
    str = QString(sop->readStdout());
    if (str.contains("detect MTU")) {
	mainwindow->statusbar->showMessage("Waiting...");
    }

    if (snstatus == 0
	&& (str.contains("hook_sc") || str.contains("downloadRate="))) {
	//create socket
	int sockfd = Sys::connect_to_server("127.0.0.1", atoi(outport));
	if (sockfd < 0) {
	    fprintf(stderr,
		    "failed to create socket, return err %d\n", sockfd);
	    return;
	}
	///launch player
	if (mainwindow->buttonplayer->isOn() && !player->isRunning()) {
	    if (forkplayer() == TRUE)
		mainwindow->buttonplayer->
		    setPaletteForegroundColor(Qt::blue);
	    else
		fprintf(stderr, "failed to launch player!\n");
	}
	///bind QSocketNotifier to socket
	snstatus =
	    new QSocketNotifier(sockfd, QSocketNotifier::Read, this);
	connect(snstatus, SIGNAL(activated(int)), SLOT(streamready(int)));
	write(sockfd, "state\ns\n", sizeof("state\ns\n"));
	write(sockfd, "state\ns\n", sizeof("state\ns\n"));
    }
}


void Fork::streamready(int fd)
{
    char buff[64];
    memset(buff, 0, sizeof(buff));

    int red = 0, size, ret;
    size = sizeof(buff);
    while (1) {
	ret =::read(fd, buff + red, size);
	if (ret <= 0)		///server shutdown
	{
	    if (ret < 0)
		perror("status socketnotifier");
	    //close socket and delete socket noitifier
	    ::close(fd);
	    delete snstatus;
	    snstatus = 0;
	    ///stop timer
	    echotimer->stop();
	    ///change statusbar interface
	    return;
	}
	if (strstr(buff, "\n"))
	    break;

	red += ret;
	size -= ret;
    }

    if (buff[0] != 10) {
	char *savept;
	strtok_r(buff, "\n", &savept);

	int value[6];
	value[0] = atoi(strtok_r(buff, " ", &savept));
	for (int i = 1; i < 6; i++) {
	    value[i] = atoi(strtok_r(NULL, " ", &savept));
	    if (i < 5)
		value[i] = value[i] / 1024;
	}

	static const char format[][10] =
	    { "%d%%", "ur=%dk", "dr=%dk", "us=%dk", "ds=%dk",
	    "peers=%d"
	};

	QString str[6];

	for (int i = 0; i < 6; i++) {
	    sprintf(buff, format[i], value[i]);
	    str[i] = buff;
	}
	mainwindow->statusbar->showMessage(str);


    } else
	printf("buff=10\n");

    ///singleshot
    echotimer->start(1000, true);
}


void Fork::echo()
{
    write(snstatus->socket(), "s\n", sizeof("s\n"));
}
